package dao;

import java.util.List;

import model.Anfrage;
import model.Person;
import model.TypStatus;

import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * WebContent/WEB-INF/lib/org.springframework.orm-3.0.3.RELEASE.jar
 */

public class PersonDao extends HibernateDaoSupport {

	/**
	 * Anlegen o. Aendern eines {@link Person} - Objektes in der Datenbank.
	 * 
	 * Alle Klassenattribute werden in der Uebergabeliste erwartet.
	 * 
	 * E-Mail-Adresse wird als Login verwendet. Somit wirft die Funktion bei
	 * Vorhandensein der E-Mail-Adresse die Exception
	 * {@link PersonExistsException}
	 * 
	 * @param nachname
	 * @param vorname
	 * @param adresse
	 * @param PLZ
	 * @param ort
	 * @param email
	 * @param password
	 * @param isAdmin
	 * @param stCouch
	 * @param stInternet
	 * @param stZeigeStadt
	 * @param stParkplatz
	 * 
	 * @throws PersonExistsException
	 */
	public void create(String nachname, String vorname, String adresse,
			String plz, String ort, String eMail, String PWD, boolean isAdmin,
			TypStatus stCouch, TypStatus stInternet, TypStatus stZeigeStadt,
			TypStatus stParkplatz) throws PersonExistsException {
		Person p = new Person();
		p.setNachname(nachname);
		p.setVorname(vorname);
		p.setAdresse(adresse);
		p.setPLZ(plz);
		p.setOrt(ort);
		p.setEMail(eMail);
		p.setPWD(PWD);
		p.setIsAdmin(isAdmin);
		p.setStateCouch(stCouch);
		p.setStateInternet(stInternet);
		p.setStateParkplatz(stParkplatz);
		p.setStateZeigeStadt(stZeigeStadt);
		save(p);
	}

	/**
	 * Anlegen o. Aendern eines {@link Person} - Objektes in der Datenbank.
	 * 
	 * E-Mail-Adresse wird als Login verwendet. Somit wirft die Funktion bei
	 * Vorhandensein der E-Mail-Adresse die Exception
	 * {@link PersonExistsException}
	 * 
	 * @param {@link Person}
	 * 
	 * @throws PersonExistsException
	 */
	public void create(Person p) throws PersonExistsException {
		Person tmp = p;
		save(tmp);
	}

	/**
	 * E-Mail-Adresse wird als Login verwendet. Diese Funktion prueft, ob die in
	 * der Parameterliste uebermittelte E-Mail-Adresse in der Datenbank schon
	 * vorhanden ist.
	 * 
	 * @param email
	 * @return boolean existsEmail
	 * 
	 */
	private boolean existsEmail(String email) {
		String queryString = "select count(PID) from Person where email = '"
				+ email + "'";
		SQLQuery query = getSession().createSQLQuery(queryString);

		if (query.list().get(0).toString() != "0") {
			return true;
		}
		return false;
	}

	/**
	 * Anlegen o. Aendern eines {@link Person} - Objektes in der Datenbank.
	 * 
	 * E-Mail-Adresse wird als Login verwendet. Somit wirft die Funktion bei
	 * Vorhandensein der E-Mail-Adresse die Exception
	 * {@link PersonExistsException}
	 * 
	 * @param {@link Person}
	 * 
	 * @throws PersonExistsException
	 */
	public Person save(Person person) throws PersonExistsException {
		if (person.getId() == 0) {
			if (existsEmail(person.getEMail())) {
				throw new PersonExistsException();
			}
		}
		HibernateTemplate template = getHibernateTemplate();
		template.saveOrUpdate(person);
		return person;
	}

	/**
	 * Gibt ein {@link Person} - Objekt der zugehoerigen, uebergebenen Id
	 * zurueck
	 * 
	 * @param id
	 * @return {@link Person}
	 * 
	 */
	public Person findById(int id) {
		HibernateTemplate template = getHibernateTemplate();
		return (Person) template.get(Person.class, id);
	}

	/**
	 * Liefert alle {@link Person} - Objekte aus der Datenbank
	 * 
	 * @return Liste aller {@link Person} - Objekte
	 */
	@SuppressWarnings("unchecked")
	public List<Person> findAll() {
		HibernateTemplate template = getHibernateTemplate();
		@SuppressWarnings("rawtypes")
		List results = template.loadAll(Person.class);
		return results;
	}

	/**
	 * Liefert alle {@link Person} - Objekte aus der Datenbank mit deren
	 * Durchschnittsbewertung aus der Anfrage-Tabelle.
	 * 
	 * @return Liste aller {@link Person} - Objekte mit Durchschnittsbewertung
	 */
	public List<Person> findAllPlusNote() {
		HibernateTemplate template = getHibernateTemplate();
		List<Person> results = template.loadAll(Person.class);

		for (Person person : results) {
			person.setAvgNote(getAvgBewertungen(person.getId()));
			person.setCountAnfragen(getCountAnfragen(person.getId()));
		}

		return results;
	}

	/**
	 * Ueberprueft ob die E-Mail mit dem Password laut Datenbank zusammenpasst
	 * und gibt gefundenes {@link Person} - Objekt zurueck.
	 * 
	 * @param email
	 * @param pwd
	 * 
	 * @return {@link Person}
	 * 
	 */
	public Person checkLogin(String email, String pwd) {
		// Moeglichkeit der Abfrage ueber Criteria
		Person person = new Person();

		if (true) {
			Criteria criteria = getSession().createCriteria(Person.class);

			// Gross- u. Kleinschreibung wird beachtet bei den Restrictions
			criteria.add(Restrictions.eq("EMail", email));
			criteria.add(Restrictions.eq("PWD", pwd));
			@SuppressWarnings("rawtypes")
			List results = criteria.list();

			if (results.size() > 0) {
				person = (Person) results.get(0);
			}
		}

		// Möglichkeit der Abfrage ueber ein SQL-Befehl
		if (false) {
			String queryString = "select * from Person where email = '" + email
					+ "' AND PWD = '" + pwd + "'";
			SQLQuery query = getSession().createSQLQuery(queryString);
			query.addEntity("person", Person.class);
			List results = query.list();

			if (results.size() > 0) {
				person = (Person) results.get(0);
			}
		}
		return person;
	}

	/**
	 * Aendert die Stati der Angebote eines {@link Person} - Objektes.
	 * 
	 * @param {@link Person}
	 * @return liefert zurueck, ob was veraendert wurde
	 * 
	 */
	public boolean saveStati(Person person) {
		String queryString = "update Person set stCouch = "
				+ person.getStateCouch().getId() + ", stInternet = "
				+ person.getStateInternet().getId() + ", stParkplatz = "
				+ person.getStateParkplatz().getId() + ", stZeigeStadt = "
				+ person.getStateZeigeStadt().getId() + " where PID = "
				+ person.getId();
		SQLQuery query = getSession().createSQLQuery(queryString);
		int result = query.executeUpdate();
		if (result > 0) {
			return true;
		}
		return false;
	}

	/**
	 * Prueft, ob zur {@link Person} bereits Anfrage (egal als Anbieter o.
	 * Suchender) bestehen.
	 * 
	 * @param UserId
	 * @return liefert zurueck, ob Anfragen zur Person vorhanden ist
	 * 
	 */
	private boolean checkExistsAnfragen2User(int pUserId) {
		String queryString = "select count(PID) from Anfrage where PID = "
				+ pUserId;
		SQLQuery query = getSession().createSQLQuery(queryString);
		// query.addEntity("person", Person.class);
		if (Integer.parseInt(query.list().get(0).toString()) != 0) {
			return true;
		}

		queryString = "select count(SID) from Anfrage where SID = " + pUserId;
		query = getSession().createSQLQuery(queryString);
		if (Integer.parseInt(query.list().get(0).toString()) != 0) {
			return true;
		}

		return false;
	}

	/**
	 * Liefert die Anzahl der Anfragen zu einer Person
	 * 
	 * @param UserId
	 * @return liefert die Anzahl zur Person
	 * 
	 */
	public int getCountAnfragen(int pUserId) {
		String queryString = "select count(PID) from Anfrage where PID = "
				+ pUserId;
		SQLQuery query = getSession().createSQLQuery(queryString);
		// query.addEntity("person", Person.class);

		return Integer.parseInt(query.list().get(0).toString());
	}

	/**
	 * Ermittelt die Durchschnittsbewertung aller Angebote einer Person.
	 * 
	 * @param UserId
	 * @return liefert die Durchschnittsbewertung aller Angebote einer Person
	 *         zurück
	 * 
	 */
	public double getAvgBewertungen(int pUserId) {
		String queryString = "select avg(bewertung) from Anfrage where PID = "
				+ pUserId + " AND bewertung <> 0";
		SQLQuery query = getSession().createSQLQuery(queryString);
		// query.addEntity("person", Person.class);
		if (!query.list().isEmpty()) {
			int ganzzahl = 0;
			double rest = 0.0;

			try {
				double avg = Double.parseDouble(query.list().get(0).toString());
				ganzzahl = (int) (avg);
				rest = avg - ganzzahl;

				if (rest <= 0.25) {
					rest = 0;
				} else {
					if (rest <= 0.75) {
						rest = 0.5;
					} else {
						rest = 0;
						ganzzahl++;
					}
				}
			} catch (Exception e) {
				return 0;
			}
			return ganzzahl + rest;
		} else {
			return 0;
		}
	}

	/**
	 * Loescht eine Person, wenn zu dieser keine Anfragen/Buchungen besteht
	 * 
	 * @param {@link Person}
	 * @exception {@link PersonDeleteException}
	 * @exception {@link IllegalArgumentException}
	 * 
	 */
	public void delete(Person person) throws Exception {
		if (person == null) {
			throw new IllegalArgumentException(); // Person darf nicht NULL sein
			// return;
		}
		if (checkExistsAnfragen2User(person.getId())) {
			throw new PersonDeleteException();
		}

		HibernateTemplate template = getHibernateTemplate();
		template.delete(person);
	}

	/**
	 * Loescht eine Person, mit allen zugehoerigen Referenzen (Buchungen,
	 * Anfragen)
	 * 
	 * @param UserId
	 * 
	 */
	public void deleteInkRef(int pId) {
		Person person = findById(pId);

		String queryString = "delete from Anfrage where PID =" + person.getId();
		SQLQuery query = getSession().createSQLQuery(queryString);
		query.addEntity("Anfrage", Anfrage.class);
		int result = query.executeUpdate();

		queryString = "delete from Anfrage where SID =" + person.getId();
		query = getSession().createSQLQuery(queryString);
		query.addEntity("Anfrage", Anfrage.class);
		result = query.executeUpdate();

		HibernateTemplate template = getHibernateTemplate();
		template.delete(person);
	}

}
